package oakclub.service;

import javapns.Push;
import javapns.notification.PushNotificationPayload;
import javapns.notification.PushedNotification;
import javapns.notification.PushedNotifications;
import oakclub.entity.NotificationEntity;
import oakclub.entity.TokenEntity;
import oakclub.entity.UserEntity;
import oakclub.global.Config;
import oakclub.global.Container;
import oakclub.model.NotificationModel;
import oakclub.utility.HttpUtility;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

public class NotificationService
{
    private final String iosKeystore = Config.get("ios.apsn.keystore");
    private final String iosPassphrase = Config.get("ios.apsn.passphrase");

    private final String androidCloudUrl = Config.get("android.cloud_url");
    private final String androidApiKey = Config.get("android.api_key");

    private final String IOS_DEFAULT_SOUND = "default";
    private final int ALERT_MAX_LENGTH = 30;

    private final Logger logger = LoggerFactory.getLogger(NotificationService.class);

    private enum Type
    {
        CHAT("chat");

        private final String val;

        private Type(String val)
        {
            this.val = val;
        }

        public String val()
        {
            return this.val;
        }
    }

    private void pushIOSNotification(String token, Type type, String alert, int badge, Map<String, Object> data)
    {
        // check token
        if(token == null || token.equals(""))
        {
            throw new IllegalArgumentException("ios token invalid");
        }

        // push
        try
        {
            PushNotificationPayload payload = PushNotificationPayload.complex();
            payload.addAlert(alert);
            payload.addSound(this.IOS_DEFAULT_SOUND);
            payload.addBadge(badge);
            payload.addCustomDictionary("type", type.val());
            payload.addCustomDictionary("data", data);
            PushedNotifications notifications = Push.payload(payload, this.iosKeystore, this.iosPassphrase, true, token);
            for(PushedNotification notification : notifications)
            {
                if(!notification.isSuccessful())
                {
                    this.logger.warn("ios: push notification failed {}", notification);
                    throw new Exception("ios: push notification failed");
                }
            }
        }
        catch(Exception e)
        {
            this.logger.warn("ios notification issue", e);
        }

    }

    private void pushAndroidNotification(String token, Type type, String alert, Map<String, Object> info)
    {
        // check token
        if(token == null || token.equals(""))
        {
            throw new IllegalArgumentException("android token invalid");
        }

        // info
        Map<String, Object> data = new HashMap<>();
        data.put("type", type.val());
        data.put("alert", alert);
        data.put("info", info);

        // params
        Map<String, Object> params = new HashMap<>();
        params.put("registration_ids", Arrays.asList(token));
        params.put("data", data);

        // push
        try
        {
            HttpUtility.sendPost(this.androidCloudUrl, params, this.androidApiKey);
        }
        catch(Exception e)
        {
            this.logger.warn("android notification issue", e);
        }
    }

    public void pushChatNotification(long userId, long targetId, String msg)
    {
        // check cache
        MemcachedService memcachedService = (MemcachedService) Container.getComponent(MemcachedService.class);
        try
        {
            Object cache = memcachedService.get(MemcachedService.Key.CHAT_NOTIFICATION, userId + '.' + targetId);
            if(cache != null)
            {
                return;
            }
        }
        catch(Exception e)
        {
            this.logger.warn("memcached issue", e);
        }

        // get info from db
        NotificationModel notificationModel = (NotificationModel) Container.getComponent(NotificationModel.class);
        NotificationEntity notification = null;
        try
        {
            notification = notificationModel.get(userId, targetId);
        }
        catch(Exception e)
        {
            return;
        }
        UserEntity user = notification.getUser();
        TokenEntity token = notification.getToken();
        int badge = notification.getBadge();

        // alert
        String alert = user.getDisplayName() + ": " + msg.replaceAll("<img[^>]+>", "(image)");
        if(alert.length() > this.ALERT_MAX_LENGTH)
        {
            alert = alert.substring(0, this.ALERT_MAX_LENGTH - 4) + "...";
        }

        // ios
        String iosToken = token.getIos();
        if(iosToken != null && !iosToken.equals(""))
        {
            Map<String, Object> data = new HashMap<>();
            data.put("profile_id", user.getProfileId());
            data.put("name", user.getDisplayName());
            this.pushIOSNotification(iosToken, Type.CHAT, alert, badge, data);
        }

        // android
        String androidToken = token.getAndroid();
        if(androidToken != null && !androidToken.equals(""))
        {
            Map<String, Object> data = new HashMap<>();
            data.put("profile_id", user.getProfileId());
            data.put("name", user.getDisplayName());
            data.put("avatar", user.getAvatar().getUrl());
            this.pushAndroidNotification(androidToken, Type.CHAT, alert, data);
        }

        // set cache
        try
        {
            memcachedService.set(MemcachedService.Key.CHAT_NOTIFICATION, userId + '.' + targetId, 1);
        }
        catch(Exception e)
        {
            this.logger.warn("memcached issue", e);
        }
    }
}
